package zelix.hack.hacks;

import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;

import net.minecraft.world.World;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import zelix.hack.Hack;
import zelix.hack.HackCategory;
import zelix.utils.hooks.visual.ChatUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AntiItemLag extends Hack {
    public static final Logger logger = FMLCommonHandler.instance().getFMLLogger();
    public int INT_ITEM_LAG_MAX = 128;
    public int INT_ITEM_LAG_DOWN_TO = 64;
    public Configuration configuration;
    public boolean antiItemLag = true;

    public AntiItemLag(){
        super("AntiItemLag" , HackCategory.ANOTHER);
    }

    @Override
    public void onPlayerTick(TickEvent.PlayerTickEvent event) {
        updateAntiItemLag();
        super.onPlayerTick(event);
    }

    @Override
    public void onClientTick(TickEvent.ClientTickEvent event){
        updateAntiItemLag();
        super.onClientTick(event);
    }

    private void updateAntiItemLag(){
        if (!antiItemLag) return;
        HashMap<Item, List<List<Entity>>> map = new HashMap<Item,List<List<Entity>>>();
        WorldClient worldClient = Minecraft.getMinecraft().world;
        if (worldClient==null) return;
        List<Entity> list = Minecraft.getMinecraft().world.getLoadedEntityList();
        if (list==null) return;
        for (int j = 0; j < list.size(); ++j) {
            Entity entity = list.get(j);
            Item item = (entity instanceof EntityItem) ? ((EntityItem) entity).getItem().getItem() : null;
            if (item!=null) {
                List<List<Entity>> list1 = (List<List<Entity>>) map.get(item);
                if (list1==null) {
                    list1 = new ArrayList<List<Entity>>();
                    map.put(item, list1);
                }
                List<Entity> targetList = null;
                for	(int i=0; i<list1.size(); i++) {
                    targetList = list1.get(i);
                    Entity entity1 = targetList.get(0);
                    if (entity.getDistanceSq(entity1) <= 1.0) {
                        break;
                    }
                    targetList = null;
                }
                if (targetList==null) {
                    targetList = new ArrayList<Entity>();
                    list1.add(targetList);
                }
                targetList.add(entity);
            }
            //boolean isWool = Block.getBlockFromItem(item) == Blocks.wool;
            //if (isWool) {
//				tmpList.add(entity);
//				list.remove(j);
//				res++;
            //}
//        	if (isWool && !showWool) {
//        		logger.log(Level.INFO, "EntityViewRenderEvent: cancel");
//        	}
        }

        int removeCount = 0;
        for (Map.Entry<Item, List<List<Entity>>> entry : map.entrySet()) {
            List<List<Entity>> list1 = entry.getValue();
            List<Entity> targetList = null;
            for	(int i=0; i<list1.size(); i++) {
                targetList = list1.get(i);
                INT_ITEM_LAG_MAX = configuration.get(Configuration.CATEGORY_GENERAL, "INT_ITEM_LAG_MAX", INT_ITEM_LAG_MAX).getInt();
                INT_ITEM_LAG_DOWN_TO = configuration.get(Configuration.CATEGORY_GENERAL, "INT_ITEM_LAG_DOWN_TO", INT_ITEM_LAG_DOWN_TO).getInt();
                if (targetList.size() > INT_ITEM_LAG_MAX) {
                    for (int j=INT_ITEM_LAG_DOWN_TO-1; j<targetList.size(); j++) {
                        removeCount++;
                        Entity entityIn = targetList.get(j);

                        if (entityIn instanceof EntityPlayer)
                        {
                            worldClient.playerEntities.remove(entityIn);
                            worldClient.updateAllPlayersSleepingFlag();
                        }

                        int x = entityIn.chunkCoordX;
                        int z = entityIn.chunkCoordZ;
                       // Method method = ReflectionHelper.findMethod(World.class, (World)worldClient, new String[]{"isChunkLoaded", "func_175680_a"}, int.class, int.class, boolean.class);
                        Method method = zelix.utils.ReflectionHelper.findMethod(World.class , (World)worldClient , new String[]{"isChunkLoaded","func_175680_a"}, int.class , int.class , boolean.class);
			                  method.setAccessible(true);
                        boolean isLoad=false;
                        try {
                            isLoad = ((Boolean)(method.invoke((World)worldClient, new Integer(x), new Integer(z), new Boolean(true)))).booleanValue();
                        }
                        catch(IllegalAccessException e) {
                            logger.log(Level.INFO, e.getMessage());
                        }
                        catch(IllegalArgumentException e) {
                            logger.log(Level.INFO, e.getMessage());
                        }
                        catch(InvocationTargetException e) {
                            logger.log(Level.INFO, e.getMessage());
                        }
                        catch(Exception e) {
                            logger.log(Level.INFO, e.getMessage());
                        }

                        if (entityIn.addedToChunk && isLoad )
                        {
                            worldClient.getChunkFromChunkCoords(x, z).removeEntity(entityIn);
                        }

                        worldClient.loadedEntityList.remove(entityIn);
                        //worldClient.onEntityRemoved(entityIn);
                    }
                }
//				targetList = list1.get(i);
//				Entity entity1 = targetList.get(0);
//				if (entity.getDistanceSqToEntity(entity1) <= 1.0) {
//					break;
//				}
//				targetList = null;
            }
        }


        if (removeCount>0)
            ChatUtils.message("antiItemLag: " + removeCount);
    }

}
